/*
 * anima/console.cc - Generic console functions.
 * Copyright (C) 2007  Mikhail Vorozhtsov
 * See the LICENSE section of the README file for details.
 */

/* $Id$ */

#include HEADER (anima,console.hh)

START_NAMESPACE (anima)

void
console::puts (const char *str)
{
  while (*str)
    putc (*str++);
}

void
console::puts (const char *str, u64_t length)
{
  for (u64_t i = 0; i < length; ++i)
    putc (str[i]);
}

void
console::print (const char *fmt, ...)
{
  va_list args;
  va_start (args, fmt);
  vprint (fmt, args);
  va_end (args);
}

void
console::warning (const char *fmt, ...)
{
  va_list args;
  va_start (args, fmt);
  puts ("WARNING: ");
  vprint (fmt, args);
  putc ('\n');
  va_end (args);
}

void
console::error (const char *fmt, ...)
{
  va_list args;
  va_start (args, fmt);
  puts ("ERROR: ");
  vprint (fmt, args);
  putc ('\n');
  va_end (args);
}

void
console::fatal (const char *fmt, ...)
{
  va_list args;
  va_start (args, fmt);
  puts ("FATAL: ");
  vprint (fmt, args);
  putc ('\n');
  va_end (args);
}

void
console::vprint (const char *fmt, va_list args)
{
  static const char digits[] =
    {
      '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
      'A', 'B', 'C', 'D', 'E', 'F'
    };

  while (*fmt)
    {
      char c = *fmt++;
      if (c != '%')
        console::putc (c);
      else
        switch (*fmt++)
          {
          case '%':
            putc ('%');
            break;
          case 'c':
            putc (va_arg (args, int));
            break;
          case 's':
            puts (va_arg (args, const char *));
            break;
          case 'S':
            {
              const char *str = va_arg (args, const char *);
              u64_t length = va_arg (args, u64_t);
              puts (str, length);
            }
            break;
          case 'p':
            {
              u64_t ptr = va_arg (args, u64_t);
              putc ('0');
              putc ('x');
              for (int i = 15; i >= 0; --i)
                putc (digits[(ptr >> i * 4) & 0x0f]);
            }
            break;
          case 'P':
            {
              u32_t ptr = va_arg (args, u32_t);
              putc ('0');
              putc ('x');
              for (int i = 7; i >= 0; --i)
                putc (digits[(ptr >> i * 4) & 0x0f]);
            }
            break;
          case 'u':
            {
              u64_t u = va_arg (args, u64_t);
              if (u == 0)
                putc ('0');
              else
                {
                  char str[21], *p;
                  str[20] = 0;
                  for (p = &str[19]; u > 0; --p, u /= 10)
                    *p = digits[u % 10];
                  puts (p + 1);
                }
            }
            break;
          }
    }
}

END_NAMESPACE

